package com.winway.framework.config;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import com.alibaba.druid.support.jakarta.StatViewServlet;
import com.alibaba.druid.support.jakarta.WebStatFilter;
import com.alibaba.druid.util.Utils;
import jakarta.servlet.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

import java.io.IOException;
import java.util.Arrays;

/**
 * Druid配置
 */
@Slf4j
@Configuration
@AutoConfigureAfter(DruidDataSourceAutoConfigure.class)
public class DruidConfig {

    private final Environment environment;
    @Value("${spring.datasource.druid.stat-view-servlet.login-username:admin}")
    private String loginUsername;
    @Value("${spring.datasource.druid.stat-view-servlet.login-password:123456}")
    private String loginPassword;

    public DruidConfig(Environment environment) {
        this.environment = environment;
    }

    /**
     * 配置Druid监控页面
     */
    @Bean
    public ServletRegistrationBean<StatViewServlet> statViewServlet() {
        log.info("配置Druid监控页面");
        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");

        // 添加IP白名单
        String allow = "";
        // 根据环境配置不同的IP白名单
        if (isProdEnvironment()) {
            log.info("生产环境模式，限制Druid监控页面访问IP");
            // 生产环境下限制IP访问
            allow = "127.0.0.1";
        } else {
            log.info("非生产环境模式，允许所有IP访问Druid监控页面");
        }

        bean.addInitParameter("allow", allow);
        // 添加IP黑名单，当白名单和黑名单重复时，黑名单优先级更高
        bean.addInitParameter("deny", "");
        // 添加控制台管理用户
        bean.addInitParameter("loginUsername", loginUsername);
        bean.addInitParameter("loginPassword", loginPassword);
        // 是否能够重置数据
        bean.addInitParameter("resetEnable", isProdEnvironment() ? "false" : "true");

        log.info("Druid监控页面配置完成，访问地址: /druid/index.html，登录用户名: {}", loginUsername);
        return bean;
    }

    /**
     * 配置web监控过滤器
     */
    @Bean
    public FilterRegistrationBean<WebStatFilter> webStatFilter() {
        log.info("配置Druid Web监控过滤器");
        FilterRegistrationBean<WebStatFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new WebStatFilter());

        // 添加过滤规则
        bean.addUrlPatterns("/*");
        // 忽略过滤格式
        bean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");

        // 在开发环境启用session统计功能
        if (!isProdEnvironment()) {
            bean.addInitParameter("sessionStatEnable", "true");
            bean.addInitParameter("sessionStatMaxCount", "1000");
            log.info("非生产环境，开启会话统计");
        }

        log.info("Druid Web监控过滤器配置完成");
        return bean;
    }

    /**
     * 去除Druid监控页面的广告
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    @Bean
    @ConditionalOnWebApplication
    @ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled", havingValue = "true", matchIfMissing = true)
    public FilterRegistrationBean removeDruidAdFilter() {
        log.info("去除Druid监控页面的广告");
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new Filter() {
            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                    throws IOException, ServletException {
                chain.doFilter(request, response);
                response.resetBuffer();
                String text = Utils.readFromResource("support/http/resources/js/common.js");
                text = text.replaceAll("this\\s*\\.\\s*buildFooter\\(\\);", "");
                response.getWriter().write(text);
            }
        });
        filterRegistrationBean.addUrlPatterns("/druid/js/common.js");
        return filterRegistrationBean;
    }

    /**
     * 检查当前是否是生产环境
     */
    private boolean isProdEnvironment() {
        String[] activeProfiles = environment.getActiveProfiles();
        return Arrays.stream(activeProfiles).anyMatch("prod"::equals);
    }
}
